//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <Bvd1.h>
#include <bulverde.h>
#include "pcf50606.h"

//#define _DBGRTC

#define MAXYEAR     (2037)

typedef struct {
    UInt8 uYear;    //0~99
    UInt8 uMonth;   //1~12
    UInt8 uDay;     //1~31
    UInt8 uHour;    //0~23
    UInt8 uMinute;  //0~59
    UInt8 uSecond;  //0~59
    UInt8 uWeekDay; //0~6
    UInt8 Reserved2;
}PackTime;

int ostDelta = 0;

INLINE UInt32 RTCTimeToSeconds(const PackTime *pRTCTime)
{
    assert(pRTCTime);

    int nMonth  = pRTCTime->uMonth;
    int nYear   = pRTCTime->uYear+2000;
    int nDate   = pRTCTime->uDay;
    nMonth -= 2;            // 1..12 -> 11,12,1..10
    if (0 >= nMonth) {
        nMonth  += 12;      // Puts Feb last since it has leap day
        nYear   -= 1;
    }

    UInt32 uSeconds = (uint_t)(nYear / 4 - nYear / 100 + nYear / 400
            + 367 * nMonth / 12 + nDate) + nYear * 365 - 719499;

    uSeconds = uSeconds * 24 + pRTCTime->uHour;    // now have hours
    uSeconds = uSeconds * 60 + pRTCTime->uMinute;  // now have minutes
    uSeconds = uSeconds * 60 + pRTCTime->uSecond;  // finally seconds

    return uSeconds;
}

INLINE void SecondsToRTCTime(uint32_t uSeconds, RTCTime *pRTCTime)
{
    assert(pRTCTime);

#define SECONDS_PER_DAY     (3600 * 24)

    uint32_t uHoursMinutesSeconds = uSeconds % SECONDS_PER_DAY;
    pRTCTime->uHours    = uHoursMinutesSeconds / 3600;
    pRTCTime->uMinutes  = (uHoursMinutesSeconds % 3600) / 60;
    pRTCTime->uSeconds  = uHoursMinutesSeconds % 60;

#define IS_LEAPYEAR(y)      \
    (((0 == (y) % 4) && (0 != (y) % 100)) || (0 == (y) % 400))
#define DAYS_PER_YEAR(y)    (IS_LEAPYEAR(y)? 366u : 365u)

    uint32_t uDays = uSeconds / SECONDS_PER_DAY;
    uint32_t uYear;
    for (uYear = 1970; uDays >= DAYS_PER_YEAR(uYear); uYear++) {
        uDays -= DAYS_PER_YEAR(uYear);
    }
    pRTCTime->uYear = uYear;

    uint32_t uDaysPerMonth[12] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };

#define DAYS_PER_MONTH(m)   (uDaysPerMonth[(m) - 1])
    if (IS_LEAPYEAR(uYear)) DAYS_PER_MONTH(2) = 29;

    uint32_t uMonth;
    for (uMonth = 1; uDays >= DAYS_PER_MONTH(uMonth); uMonth++) {
        uDays -= DAYS_PER_MONTH(uMonth);
    }
    pRTCTime->uMonth = uMonth;

    pRTCTime->uDate = uDays + 1;
}

void _GetRTCTime(PackTime *p)
{
    uint32_t uYMD = RYCR;
    uint32_t uHMS = RDCR;

    p->uYear = ((uYMD >> 9) & 0xfff) - 2000;//Year
    p->uMonth    = (uYMD >> 5) & 0xf;//Month
    p->uDay     = (uYMD & 0x1f);//Day of Month

    p->uHour    = (uHMS >> 12) & 0x1f;//Hour
    p->uMinute  = (uHMS >> 6) & 0x3f;//Minnute
    p->uSecond  = (uHMS & 0x3f);//Second

    p->uWeekDay  = ((uHMS >> 17) & 0x7) - 1;//Day of Week

}

void _SetRTCTime(int h,int m,int s)
{
    uint32_t uHMS = RDCR;
    uHMS &= (7 << 17);

    uHMS = ((h & 0x1f) << 12) | ((m&0x3f) << 6) | (s & 0x3f);

    RDCR = uHMS;
}

void _SetRTCDate(int w,int y,int md,int d)
{
    uint32_t uYMD = 0;
    uint32_t uHMS = RDCR;

    uYMD = ((y & 0xfff) << 9) | ((md & 0xf) << 5) | (d & 0x1f);

    uHMS &= ~(7 << 17);
    uHMS |= ((w & 0x7) << 17);

    RYCR = uYMD;
    RDCR = uHMS;
}

EXTERN void DzSyncSystemTime();
void _Pcf_UpdateRTCTime(unsigned long Elapsed);

int bcd2dec(char bValue)
{
    return (bValue>>4)*10 + (bValue&0xf);
}

char dec2bcd(int dValue)
{
    dValue&=0xff;
    char lowH = (char)dValue%10;
    char highH = (char)((dValue - lowH)/10);
    return highH<<4|lowH;
}

/*time register*/

int readRTCHRvalue()
{//0-23
    return bcd2dec(readPCFregister(PCF50606_RTCHR));
}

int readRTCHRAvalue()
{//0-23
    return bcd2dec(readPCFregister(PCF50606_RTCHRA));
}

void writeRTCHRvalue(int value)
{
    writePCFregister(PCF50606_RTCHR,dec2bcd(value));
}

void writeRTCHRAvalue(int value)
{
    writePCFregister(PCF50606_RTCHRA,dec2bcd(value));
}

int readRTCMNvalue()
{//0-59
    return bcd2dec(readPCFregister(PCF50606_RTCMN));
}

int readRTCMNAvalue()
{//0-59
    return bcd2dec(readPCFregister(PCF50606_RTCMNA));
}

void writeRTCMNvalue(int value)
{
    writePCFregister(PCF50606_RTCMN,dec2bcd(value));
}

void writeRTCMNAvalue(int value)
{
    writePCFregister(PCF50606_RTCMNA,dec2bcd(value));
}

int readRTCSCvalue()
{//0-59
    return bcd2dec(readPCFregister(PCF50606_RTCSC));
}

int readRTCSCAvalue()
{//0-59
    return bcd2dec(readPCFregister(PCF50606_RTCSCA));
}

void writeRTCSCvalue(int value)
{
    writePCFregister(PCF50606_RTCSC,dec2bcd(value));
}

void writeRTCSCAvalue(int value)
{
    writePCFregister(PCF50606_RTCSCA,dec2bcd(value));
}

/*date register*/

int readRTCWDvalue()
{//0-6
    return bcd2dec(readPCFregister(PCF50606_RTCWD));
}

int readRTCWDAvalue()
{//0-6
    return bcd2dec(readPCFregister(PCF50606_RTCWDA));
}

void writeRTCWDvalue(int value)
{
    writePCFregister(PCF50606_RTCWD,dec2bcd(value));
}

void writeRTCWDAvalue(int value)
{
    writePCFregister(PCF50606_RTCWDA,dec2bcd(value));
}

int readRTCDTvalue()
{//1-31
    return bcd2dec(readPCFregister(PCF50606_RTCDT));
}

int readRTCDTAvalue()
{//1-31
    return bcd2dec(readPCFregister(PCF50606_RTCDTA));
}

void writeRTCDTvalue(int value)
{
    writePCFregister(PCF50606_RTCDT,dec2bcd(value));
}

void writeRTCDTAvalue(int value)
{
    writePCFregister(PCF50606_RTCDTA,dec2bcd(value));
}

int readRTCMTvalue()
{//1-12
    return bcd2dec(readPCFregister(PCF50606_RTCMT));
}

int readRTCMTAvalue()
{//1-12
    return bcd2dec(readPCFregister(PCF50606_RTCMT));
}

void writeRTCMTvalue(int value)
{
    writePCFregister(PCF50606_RTCMT,dec2bcd(value));
}

void writeRTCMTAvalue(int value)
{
    writePCFregister(PCF50606_RTCMTA,dec2bcd(value));
}

int readRTCYRvalue()
{//0-99
    return bcd2dec(readPCFregister(PCF50606_RTCYR));
}

int readRTCYRAvalue()
{//0-99
    return bcd2dec(readPCFregister(PCF50606_RTCYR));
}

void writeRTCYRvalue(int value)
{
    writePCFregister(PCF50606_RTCYR,dec2bcd(value));
}

void writeRTCYRAvalue(int value)
{
    writePCFregister(PCF50606_RTCYRA,dec2bcd(value));
}

void _Pcf_SyncRTCTime()
{
    RTCTime t;
    t.uHours = readRTCHRvalue();
    t.uMinutes = readRTCMNvalue();
    t.uSeconds = readRTCSCvalue();

    //readRTCWDvalue();
    int y = readRTCYRvalue() + 2000;
    if (y < 2000 || y > MAXYEAR) {
        y = 2000;//reset
    }
    t.uYear = y;
    t.uMonth = readRTCMTvalue();
    t.uDate = readRTCDTvalue();

    BspSetRTCTime(&t);
}

unsigned long _GetElapsed()
{
    PackTime t;
    _GetRTCTime(&t);
    return RTCTimeToSeconds(&t) - ostDelta;
}

//set time and date register
ECode setRTCtime(int h,int m,int s)
{//attention,there is a 3 second delay.
    unsigned long Elapsed = _GetElapsed();
#if defined(_DBGRTC)
    cprintf("setRTCtime %d:%d:%d\n", h, m, s);

    PackTime t;
    _GetRTCTime(&t);
    cprintf("------current %d:%d:%d %d:%d:%d (%d)\n",
        t.uYear, t.uMonth, t.uDay,
        t.uHour, t.uMinute, t.uSecond, t.uWeekDay);
#endif

    _SetRTCTime(h, m, s);

    _Pcf_UpdateRTCTime(Elapsed);

    return NOERROR;
}

ECode setRTCdate(int w,int y,int md,int d)
{
    unsigned long Elapsed = _GetElapsed();
#if defined(_DBGRTC)
    cprintf("setRTCdate %d %d:%d:%d\n", w, y, md, d);

    PackTime t;
    _GetRTCTime(&t);
    cprintf("------current %d:%d:%d %d:%d:%d (%d)\n",
        t.uYear, t.uMonth, t.uDay,
        t.uHour, t.uMinute, t.uSecond, t.uWeekDay);
#endif

    //check year [2000~2037]
    if (y < 2000) y += 2000;
    if (y < 2000 || y > MAXYEAR) {
        cprintf("INVALID YEAR VALUE\n");
        return E_ACCESS_DENIED;
    }
    if (w >= 0 && w <= 6) {
        w += 1;
    }
    else {
        w = 1;
    }

    _SetRTCDate(w, y, md, d);

    _Pcf_UpdateRTCTime(Elapsed);

    return NOERROR;
}

ECode setRTCdatetime(SystemTime *pSystemTime)
{
    RTCTime t;
    SecondsToRTCTime(pSystemTime->seconds, &t);

    unsigned long Elapsed = _GetElapsed();
#if defined(_DBGRTC)
    cprintf("setRTCdatetime %d:%d:%d %d:%d:%d\n",
        t.uYear, t.uMonth, t.uDate, t.uHours, t.uMinutes, t.uSeconds);
#endif

    //check year [2000~2037]
    int y = t.uYear;
    if (y < 2000 || y > MAXYEAR) {
        cprintf("INVALID YEAR VALUE\n");
        return E_ACCESS_DENIED;
    }
    t.uYear = y;

    _SetRTCDate(1/*Unpredictable*/, t.uYear, t.uMonth, t.uDate);
    _SetRTCTime(t.uHours, t.uMinutes, t.uSeconds);

    _Pcf_UpdateRTCTime(Elapsed);

    return NOERROR;

}

void setRTCAtime(int h,int m,int s)
{
    writeRTCHRAvalue(h);
    //DzDelay(1000*1000);
    writeRTCMNAvalue(m);
    //DzDelay(1000*1000);
    writeRTCSCAvalue(s);
    //DzDelay(1000*1000);
}

void setRTCAdate(int w,int y,int m,int d)
{
    writeRTCWDAvalue(w);
    //DzDelay(1000*1000);
    writeRTCYRAvalue(y);
    //DzDelay(1000*1000);
    writeRTCMTAvalue(m);
    //DzDelay(1000*1000);
    writeRTCDTAvalue(d);
    //DzDelay(1000*1000);
}

void dumpRTCtime()
{
    //dump pcf rtc info
    int h = readRTCHRvalue();
    int m = readRTCMNvalue();
    int s = readRTCSCvalue();
    int w = readRTCWDvalue();
    int y = readRTCYRvalue();
    int mt = readRTCMTvalue();
    int d = readRTCDTvalue();
    cprintf("\n------RTC  Time  %d:%d:%d %d:%d:%d (%d)\n", y+2000,mt,d,h,m,s,w);

    y = readRTCYRAvalue();
    mt = readRTCMTAvalue();
    d = readRTCDTAvalue();
    h = readRTCHRAvalue();
    m = readRTCMNAvalue();
    s = readRTCSCAvalue();
    w = readRTCWDAvalue();
    cprintf("------RTC Alarm  %d:%d:%d %d:%d:%d (%d) (%s)\n\n", y+2000,mt,d,h,m,s,w,
        (!(readPCFregister(PCF50606_INT1M) & 0x80)
                && (readPCFregister(PCF50606_OOCC1)&0x10))?"En":"Ds");

    //dump bulverde rtc info
    PackTime t;
    _GetRTCTime(&t);

    //dump os time info
    SystemTime st;
    DzGetSystemTime(&st);
    RTCTime rt;
    SecondsToRTCTime(st.seconds, &rt);
    st.microseconds /= 1000;

    int dms = (st.seconds-RTCTimeToSeconds(&t))*1000+st.microseconds;

    cprintf("------Hard Time  %d:%d:%d %d:%d:%d\n",
        t.uYear+2000, t.uMonth, t.uDay,
        t.uHour, t.uMinute, t.uSecond);

    cprintf("------Soft Time  %d:%d:%d %d:%d:%d:%d  Delta %d\n\n",
        rt.uYear, rt.uMonth, rt.uDate,
        rt.uHours, rt.uMinutes, rt.uSeconds, st.microseconds, dms);

    return ;
}

void enableRTCalarm()
{
    writePCFregister(PCF50606_INT1M,readPCFregister(PCF50606_INT1M)&~0x80);//enable rtc alarm
    writePCFregister(PCF50606_OOCC1,readPCFregister(PCF50606_OOCC1)|0x10);//enable rtc wakeup
}

void disableRTCalarm()
{
    writePCFregister(PCF50606_INT1M,readPCFregister(PCF50606_INT1M)|0x80);//disable rtc alarm
    writePCFregister(PCF50606_OOCC1,readPCFregister(PCF50606_OOCC1)&~0x10);//disable rtc wakeup
}

void testRTCtime(int mdur)
{
    int h = readRTCHRvalue();
    int m = readRTCMNvalue();
    int s = readRTCSCvalue();
    int w = readRTCWDvalue();
    int y = readRTCYRvalue();
    int mt = readRTCMTvalue();
    int d = readRTCDTvalue();
    cprintf("time now is :%d:%d:%d,weekday:%d,date :%d:%d:%d\n",h,m,s,w,y,mt,d);
    cprintf("rtc wakeup enabled?%d\n",readPCFregister(PCF50606_OOCC1)&0x10);
    m+=mdur;
    if(m>60)
    {
        m-=60;
        h+=1;
    }
    setRTCAtime(h,m,s);
    setRTCAdate(w,y,mt,d);
    writePCFregister(PCF50606_OOCC1,readPCFregister(PCF50606_OOCC1)|0x10);//enable rtc wakeup
    int ha = readRTCHRAvalue();
    int ma = readRTCMNAvalue();
    int sa = readRTCSCAvalue();
    int wa = readRTCWDAvalue();
    int ya = readRTCYRAvalue();
    int mta = readRTCMTAvalue();
    int da = readRTCDTAvalue();
    cprintf("alarm time is :%d:%d:%d,weekday:%d,date :%d:%d:%d\n",ha,ma,sa,wa,ya,mta,da);
    cprintf("alarm set\n");
    return;
}

class CRTC : public CDeviceDriver {
public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf &buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf &inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose(){}

};

static CRTC g_RTC;
ECode CRTC::Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode  CRTC::Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf &buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CRTC::Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf &inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    //cprintf("+++++++++RTC::Control %d\n", nControlCode);
    switch(nControlCode) {
        case 0: {//enable rtc alarm,default:enabled
            enableRTCalarm();
            break;
        }
        case 1: {//disable rtc alarm
            disableRTCalarm();
            break;
        }
        case 2: {//get rtc time info
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            int h = readRTCHRvalue();//hour:0-23
            int m = readRTCMNvalue();//minute:0-59
            int s = readRTCSCvalue();//second:0-59
            pOutBuffer->Copy((Byte *)&h,4);
            pOutBuffer->Append((Byte *)&m,4);
            pOutBuffer->Append((Byte *)&s,4);
            pOutBuffer->SetUsed(12);
#if defined(_DBGRTC)
            dumpRTCtime();
#endif
            break;
        }
        case 3: {//get rtc date info
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            int w = readRTCWDvalue();//weekday:0-6,0 stand for Sunday
            int y = readRTCYRvalue();//year:00-99
            int mt = readRTCMTvalue();//month:01-12
            int d = readRTCDTvalue();//day:01-31
            pOutBuffer->Copy((Byte *)&w,4);
            pOutBuffer->Append((Byte *)&y,4);
            pOutBuffer->Append((Byte *)&mt,4);
            pOutBuffer->Append((Byte *)&d,4);
            pOutBuffer->SetUsed(16);
            break;
        }
        case 4://get rtc alarm time info,
        {
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            int ha = readRTCHRAvalue();//hour:0-23
            int ma = readRTCMNAvalue();//minute:0-59
            int sa = readRTCSCAvalue();//second:0-59
            pOutBuffer->Copy((Byte *)&ha,4);
            pOutBuffer->Append((Byte *)&ma,4);
            pOutBuffer->Append((Byte *)&sa,4);
            pOutBuffer->SetUsed(12);
            break;
        }
        case 5:{//get rtc alarm date info
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            int wa = readRTCWDAvalue();//weekday:0-6,0 stand for Sunday
            int ya = readRTCYRAvalue();//year:00-99
            int mta = readRTCMTAvalue();//month:01-12                    ;
            int da = readRTCDTAvalue();//day:01-31
            pOutBuffer->Copy((Byte *)&wa,4);
            pOutBuffer->Append((Byte *)&ya,4);
            pOutBuffer->Append((Byte *)&mta,4);
            pOutBuffer->Append((Byte *)&da,4);
            pOutBuffer->SetUsed(16);
            break;
        }
        case 6://set rtc time info
        {
            if(inBuffer.GetCapacity()<12)return E_INVALID_ARGUMENT;
            int * p = (int *)inBuffer.GetPayload();
            setRTCtime(p[0],p[1],p[2]);
            break;
        }
        case 7://set rtc date info
        {
            if(inBuffer.GetCapacity()<16)return E_INVALID_ARGUMENT;
            int * p = (int *)inBuffer.GetPayload();
            return setRTCdate(p[0],p[1],p[2],p[3]);
            break;
        }
        case 8://set rtc alarm time
        {
            if(inBuffer.GetCapacity()<12)return E_INVALID_ARGUMENT;
            int * p = (int *)inBuffer.GetPayload();
            setRTCAtime(p[0],p[1],p[2]);
            break;
        }
        case 9://set rtc alarm date
        {
            if(inBuffer.GetCapacity()<16)return E_INVALID_ARGUMENT;
            int * p = (int *)inBuffer.GetPayload();
            setRTCAdate(p[0],p[1],p[2],p[3]);
            break;
        }
        case 10://set rtc date & time
        {
            if(inBuffer.GetCapacity()<(int)sizeof(SystemTime))return E_INVALID_ARGUMENT;
            return setRTCdatetime((SystemTime *)inBuffer.GetPayload());
            break;
        }
        case 11://Sync os time
        {
            DzSyncSystemTime();
            dumpRTCtime();
            break;
        }
        case 12://Get elapse seconds
        {
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            unsigned long Elapsed = _GetElapsed();
            pOutBuffer->Copy((Byte *)&Elapsed,4);
            pOutBuffer->SetUsed(4);
            break;
        }
        case 13://Get alarm state
        {
            UInt32 bEnableAlarm = !(readPCFregister(PCF50606_INT1M) & 0x80)
                && (readPCFregister(PCF50606_OOCC1)&0x10);

            
            pOutBuffer->Copy((Byte *)&bEnableAlarm,4);
            pOutBuffer->SetUsed(4);
            break;
        }
        default :break;
    }
    return NOERROR;
}

void PoNotifyEvent(int evNum, void *pParameter);

void OnAlarm(void *pvDevice, bool *bArg)
{
    EmIsrParameter Param;
    Param.nParameter1 = Param.nParameter2 = 0;
    Param.nParameter3 = Param.nParameter4 = 0;

    PackTime t;
    t.uYear = readRTCYRAvalue();
    t.uMonth = readRTCMTAvalue();
    t.uDay = readRTCDTAvalue();
    t.uHour = readRTCHRAvalue();
    t.uMinute = readRTCMNAvalue();
    t.uSecond= readRTCSCAvalue();
    //readRTCWDAvalue();

    cprintf("alarm at %d:%d:%d %d:%d:%d\n",
        t.uYear, t.uMonth, t.uDay, t.uHour, t.uMinute, t.uSecond);
    memcpy(&Param, &t, sizeof(PackTime));
    PoNotifyEvent(113, &Param);//rtc alarm event
    cputs("On Alarm\n");
    dumpRTCtime();
}

int CaculateWeekDay( // using kslarsen formula
    /* [in] */ Int32 y,
    /* [in] */ Int32 m,
    /* [in] */ Int32 d)
{
    if (m == 1 || m == 2) {
        m += 12;
        y--;
    }
    return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7;
}

void AdjustRTCDateTime(void * pArg)
{
    PackTime t;
    _GetRTCTime(&t);

    t.uWeekDay = (UInt8)CaculateWeekDay(t.uYear+2000, t.uMonth, t.uDay);

#if defined(_DBGRTC)
    cprintf("Adjust with %d:%d:%d %d:%d:%d (%d)\n",
        t.uYear, t.uMonth, t.uDay,
        t.uHour, t.uMinute, t.uSecond, t.uWeekDay);
#endif

    writeRTCSCvalue(t.uSecond);
    DzSleep(100, NULL);
    writeRTCMNvalue(t.uMinute);
    DzSleep(100, NULL);
    writeRTCHRvalue(t.uHour);
    DzSleep(100, NULL);

    writeRTCWDvalue(t.uWeekDay);
    //DzSleep(100, NULL);
    writeRTCYRvalue(t.uYear);
    //DzSleep(100, NULL);
    writeRTCMTvalue(t.uMonth);
    //DzSleep(100, NULL);
    writeRTCDTvalue(t.uDay);

    DzSleep(100, NULL);

#if defined(_DBGRTC)
    dumpRTCtime();
#endif

}

void _Pcf_UpdateRTCTime(unsigned long Elapsed)
{
    DzDelay(1000*1000);

    ostDelta += _GetElapsed() - Elapsed - 1;

    PackTime t;
    _GetRTCTime(&t);
#if defined(_DBGRTC)
    cprintf("------Update Elapse Delta %d\n", ostDelta);
    cprintf("------Update with %d:%d:%d %d:%d:%d (%d)\n",
        t.uYear, t.uMonth, t.uDay,
        t.uHour, t.uMinute, t.uSecond, t.uWeekDay);
#endif

    DzSyncSystemTime();//Sync os time

    EmIsrParameter Param;
    Param.nParameter1 = Param.nParameter2 = 0;
    Param.nParameter3 = Param.nParameter4 = 0;

    memcpy(&Param, &t, sizeof(PackTime));
    EmPostEventByIsr(114, &Param);//send time change event

    NotifyByIsr(EVENT_POWER,(int)AdjustRTCDateTime,(void *)0);

}

void RTCInit()
{
    writePCFregister(PCF50606_OOCC1,readPCFregister(PCF50606_OOCC1)|0x20);//enable rtc wakeup
    Drv_PcfIrqInstall(PCF50606_ALARMM_IRQ,NULL,(void *)OnAlarm);//register alarm handler function
    dumpRTCtime();
    ostDelta = _GetElapsed();
}

EXTERN IDeviceDriver * CDECL CreateRTC(uint_t uDeviceNo, void *pvParameter)
{
    RTCInit();
    return &g_RTC;
}
